<template>
  <el-form-item class="tree-item-list" :class="{ empty: (dataList || []).length <= 0 }">
    <template v-slot:label>
      <el-row type="flex" justify="space-between" align="middle" style="width: 100%">
        <span>{{ label }}</span>
        <right-add-btn
          class="add-btn"
          type="text"
          icon="el-icon-circle-plus"
          :disabled="disabled || !supportAdd || maxCount <= (dataList || []).length"
          @click.prevent.stop="onEditItem()"
          >添加</right-add-btn
        >
      </el-row>
    </template>
    <el-row style="overflow: hidden; height: 100%; display: inline-block; width: 100%">
      <el-tree
        class="list-item"
        :data="dataList"
        :node-key="prop.id"
        :draggable="supportSort"
        :props="prop"
        :allow-drop="nodeAllowDrop"
        @node-drag-end="onDragEnd"
      >
        <template #default="{ data }">
          <div class="item" style="padding: 0px 15px 0px 5px; width: 100%">
            <el-row
              type="flex"
              align="middle"
              justify="space-between"
              style="padding: 6px 0px; min-height: 32px"
            >
              <el-link
                style="line-height: 20px; color: #333333; font-size: 12px"
                :disabled="disabled"
                @click.stop="onEditItem(data)"
              >
                <slot v-if="hasSlot" :data="data" />
                <span v-else>{{ getItemLabel(data) }}</span>
              </el-link>
              <div class="right" style="line-height: 20px; font-size: 12px">
                <slot name="right" :data="data" />
              </div>
            </el-row>
            <el-icon
              style="margin-left: 8px; color: #333"
              class="close-btn"
              :class="{ disabled: getItemDisabled(data) }"
              @click.stop="onDeleteItem(data)"
            >
              <Remove />
            </el-icon>
          </div>
        </template>
      </el-tree>
    </el-row>
  </el-form-item>
</template>

<script setup lang="ts">
import { getCurrentInstance } from 'vue';
import { ANY_OBJECT } from '@/types/generic';
import { Remove } from '@element-plus/icons-vue';

const props = withDefaults(
  defineProps<{
    label: string;
    data?: ANY_OBJECT | ANY_OBJECT[];
    disabled?: boolean;
    /**
     * 最大项数，当达到最大项数，则不能添加数据
     */
    maxCount?: number;
    /**
     * 是否支持拖拽排序，默认为false
     */
    supportSort?: boolean;
    /**
     * 是否支持添加
     */
    supportAdd?: boolean;
    dragGroup?: string;
    prop?: ANY_OBJECT;
    addText?: string;
    nodeAllowDrop?: (draggingNode: ANY_OBJECT, dropNode: ANY_OBJECT, type: string) => boolean;
  }>(),
  {
    disabled: false,
    supportSort: false,
    supportAdd: true,
    dragGroup: 'componentsGroup',
    prop: () => {
      return {
        // 数据显示字段
        label: 'name',
        // 数据值字段
        value: 'id',
        // 数据disabled字段
        disabled: undefined,
      };
    },
    nodeAllowDrop: () => {
      return (draggingNode, dropNode, type) => {
        return true;
      };
    },
  },
);

const emit = defineEmits(['add', 'edit', 'delete', 'dragEnd', 'update:data']);

const hasSlot = computed(() => {
  return getCurrentInstance()?.slots.default;
});

const dataList = computed({
  get: () => {
    if (props.data == null) return [];
    let dataList = Array.isArray(props.data) ? props.data : [props.data];
    return dataList;
  },
  set: value => {
    emit('update:data', value);
  },
});

const getItemDisabled = item => {
  let itemDisabled = false;
  if (item != null && props.prop.disabled != null) {
    if (typeof props.prop.disabled === 'function') {
      itemDisabled = props.prop.disabled(item);
    } else {
      itemDisabled = item[props.prop.disabled];
    }
  }
  return props.disabled || item == null || itemDisabled;
};

const onEditItem = item => {
  if (props.disabled) return;
  if (item == null) {
    emit('add');
  } else {
    emit('edit', item);
  }
};

const onDeleteItem = item => {
  if (getItemDisabled(item)) return;
  emit('delete', item);
};

const getItemValue = item => {
  if (typeof props.prop.value === 'function') return props.prop.value(item);
  return item[props.prop.value];
};

const getItemLabel = item => {
  if (typeof props.prop.label === 'function') return props.prop.label(item);
  return item[props.prop.label];
};

const onDragEnd = (draggingNode, dropNode, dropType) => {
  if (props.disabled) return;
  emit('dragEnd', draggingNode, dropNode, dropType);
};
</script>

<style scoped>
.tree-item-list .item {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.tree-item-list ::v-deep .el-form-item__label {
  width: 100%;
}

.tree-item-list ::v-deep .el-tree-node__content {
  border-radius: 4px;
  border: 1px solid #e8e8e8;
  background: white;
  padding: 15px 0px;
}

.tree-item-list ::v-deep .el-tree-node__children .el-tree-node {
  margin-top: 8px;
}

.tree-item-list ::v-deep .el-tree-node + .el-tree-node {
  margin-top: 8px;
}

.tree-item-list.empty ::v-deep .el-form-item__content {
  height: 0px;
}

.tree-item-list ::v-deep .el-tree-node__expand-icon.is-leaf {
  display: none;
}

.tree-item-list ::v-deep .el-tree-node__children .el-tree-node__expand-icon.is-leaf {
  display: block;
}
</style>

<style lang="scss" scoped>
.add-btn {
  position: relative;
  z-index: 9;
  margin-left: 5px;
  font-size: 14px;
  color: $color-primary;
  cursor: pointer;
}

.close-btn {
  cursor: pointer;
}

.close-btn.disabled {
  cursor: not-allowed;
}
</style>
